#ifndef MANAGER_H
#define MANAGER_H

#include <map>
#include <vector>

#include <wx/event.h>
#include <wx/dynarray.h>
#include <wx/artprov.h>
#include <wx/thread.h>

#include "tux.h"
#include "MsnContact.h"

class UserConfig;

class MsnContact;
class MsnGroup;
class MsnSession;

class ProfileMessage;

class ContactManager;
class SessionManager;

class ServerConnection;
class SessionConnection;


enum MessengerStatus
{
	MESSENGER_NEW = 0,
	MESSENGER_CONNECTING,
	MESSENGER_SIGNED_IN,
	MESSENGER_SIGNED_OUT,
	MESSENGER_CONNECTION_FAILED,
	MESSENGER_CONNECTION_BROKEN,
	MESSENGER_AUTHENTICATION_FAILED
};

class MsnMessenger : public wxEvtHandler
{
	friend class MsnSession;
	friend class ServerConnection;

typedef std::vector<MsnSession*> SessionList;

private:
    ServerConnection* serverConnection;

private:
	wxString userPassport;
    wxString userPassword;

	wxString externalIP;
	wxString internalIP;

    wxString initialStatus;

	MessengerStatus messengerStatus;

	MsnContact* user;

	int totalCount;

	UserConfig* userConfig;

    ContactManager* contactManager;
	SessionManager* sessionManager;
	wxEvtHandler* msnEventListener;

public:
    MsnMessenger();
    ~MsnMessenger();

		void RegisterEventListener(wxEvtHandler* evtHandler){msnEventListener = evtHandler;}
		void PostEvent(wxEvent& event);

		bool IsAlive();
        bool IsConnected();

		bool IsBehindWall();

		int GetMessengerStatus(){return messengerStatus;}

        wxString GetUserPassport(){return userPassport;}

		wxString GetExternalIP(){return externalIP;}
		wxString GetInternalIP(){return internalIP;}

		MsnContact* GetUser(){return user;}

        wxString GetHomeDirectory();
		wxString GetHistoryDirectory();
		wxString GetPictureDirectory();
		wxString GetFileTransferDirectory();

		ContactManager* GetContactManager(){return contactManager;}
		SessionManager* GetSessionManager(){return sessionManager;}
        UserConfig* GetUserConfig(){return userConfig;}

		wxString GetDisplayName(){return user->GetName();}
        wxString GetDisplayName(const wxString& email);
		
		wxString GetUserStatus(){return user->GetStatus();}

		wxString GetDisplayPicture();

    public:
        void SignIn(const wxString& username, const wxString& password, const wxString& status);
        void SignOut();

        void Ping();

		void ChangeStatusToIdle(bool isIdle);

        void ChangeName(const wxString& name);
        void ChangeStatus(const wxString& status);

		void ChangeDisplayPicture(wxImage& image);

        void AddContact(const wxString& passport, const wxString& list);
		void AddContactToForwardList(const wxString& passport);
		void AddContactToAllowedList(const wxString& passport);
        void AddContactToGroup(const wxString& contactID, const wxString& groupID);

        void BlockContact(const wxString& passport);
		void UnBlockContact(const wxString& passport);
        void RemoveContact(const wxString& contactID,const wxString& groupID);
		void DeleteContact(MsnContact* contact);

        void AddGroup(const wxString& name);
        void DeleteGroup(const wxString& groupID);
        void RenameGroup(const wxString& groupID, const wxString& newName);
	
    public:
        void OnSignedIn(const wxString& passport);
        void OnSignedOut();

		void OnConnectionBroken();
		void OnConnectionFailed();

		void OnAuthenticationFailed();

		void OnProfileMessageReceived(ProfileMessage* msg);

		void OnSynchronizationReceived(const wxString& serverVersion, int groupCount, int contactCount);
		void OnGroupReceived(MsnGroup* group);
		void OnContactReceived(MsnContact* contact);
		

		void OnContactStatusChanged(const wxString& passport, const wxString& status);
		void OnContactNameChanged(const wxString& passport, const wxString& name);

		void OnContactObjectChanged(const wxString& passport, const wxString& msnObject);

		void OnUserNameReceived(const wxString& code);
		void OnUserStatusChanged(const wxString& code);

		void OnContactAdded(MsnContact* contact);
        void OnContactAddedToGroup(const wxString& contactID,const wxString& groupID);
		
		void OnContactAddedToForwardList(MsnContact* contact);
		void OnContactAddedToForwardList(const wxString& passport, const wxString& contactID, const wxString& name);
		void OnContactAddedToAllowedList(const wxString& passport);
		void OnContactAddedToBlockedList(const wxString& passport);
		void OnContactAddedToReversedList(const wxString& passport, const wxString& name);

		void OnContactRemovedFromGroup(const wxString& contactID, const wxString& groupID);

		void OnContactRemovedFromForwardList(const wxString& contactID);
		void OnContactRemovedFromAllowedList(const wxString& passport);
		void OnContactRemovedFromBlockedList(const wxString& passport);
		void OnContactRemovedFromReversedList(const wxString& passport);

		void OnGroupAdded(const wxString& groupID, const wxString& groupName);
		void OnGroupRemoved(const wxString& groupID);
		void OnGroupRenamed(const wxString& groupID, const wxString& groupName);

	public:
        void OpenLogDirectory();
        void OpenFileDirectory();

		int StartSession();

	private:
		void Reset();

		void DeleteServerConnection();

		void CheckSynchronization();
		void SynchronizeContacts();

        void AddRecentContact(const wxString& contact);


DECLARE_EVENT_TABLE()

};

/*

class MsnEvent : public wxNotifyEvent
{
DECLARE_DYNAMIC_CLASS( MsnEvent )

private:
    SessionConnection* session;

public:
	MsnEvent( wxEventType t = wxEVT_NULL, int id=0):wxNotifyEvent(t,id){}
	MsnEvent(const MsnEvent& e):wxNotifyEvent(e){session = e.session;}

    SessionConnection* GetSession(){return session;}
    void SetSession(SessionConnection* _session){session = _session;}

	virtual wxEvent* Clone(){return new MsnEvent(*this);}

};


typedef void (wxEvtHandler::*MsnEventFunction)(MsnEvent&);

// it may also be convenient to define an event table macro for this event type
#define EVT_MSN_SESSION_CLOSE(id, fn) \
    DECLARE_EVENT_TABLE_ENTRY( \
        wxEVT_MSN_SESSION_CLOSE, id, wxID_ANY, \
        (wxObjectEventFunction)   \
        (MsnEventFunction) &fn, \
        (wxObject *) NULL \
    ),
*/

#endif

